// File: jmcomic-core/src/main/java/dev/jukomu/jmcomic/exception/CloudflareChallengeException.java
package dev.jukomu.jmcomic.exception;

import dev.jukomu.common.util.net.IResponse;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 当遇到Cloudflare人机验证挑战时抛出的异常。
 * 携带解决挑战所需的信息，例如挑战页面的URL和当前的CookieJar。
 */
public class CloudflareChallengeException extends JmcomicException {

    public static final String DESCRIPTION = "Cloudflare人机验证挑战异常";

    private final String challengeUrl; // 挑战页面的URL
    private final IResponse challengeResponse; // 挑战页面的原始响应
    private final CookieJar currentCookieJar; // 遇到挑战时的CookieJar实例

    /**
     * 构造函数。
     *
     * @param message           异常消息
     * @param context           异常上下文Map
     * @param challengeUrl      挑战页面的URL
     * @param challengeResponse 挑战页面的原始响应
     * @param currentCookieJar  遇到挑战时的CookieJar实例
     */
    public CloudflareChallengeException(String message, Map<String, Object> context,
                                        String challengeUrl, IResponse challengeResponse, CookieJar currentCookieJar) {
        super(message, context);
        this.challengeUrl = Objects.requireNonNull(challengeUrl, "Challenge URL cannot be null.");
        this.challengeResponse = Objects.requireNonNull(challengeResponse, "Challenge Response cannot be null.");
        this.currentCookieJar = Objects.requireNonNull(currentCookieJar, "Current CookieJar cannot be null.");
    }

    /**
     * 获取挑战页面的URL。
     *
     * @return 挑战URL
     */
    public String getChallengeUrl() {
        return challengeUrl;
    }

    /**
     * 获取挑战页面的原始响应。
     *
     * @return 挑战响应
     */
    public IResponse getChallengeResponse() {
        return challengeResponse;
    }

    /**
     * 获取遇到挑战时的CookieJar实例。
     *
     * @return 当前CookieJar
     */
    public CookieJar getCurrentCookieJar() {
        return currentCookieJar;
    }

    /**
     * 获取当前CookieJar中所有Cookie的Map表示。
     *
     * @return Cookie名称到值的Map
     */
    public Map<String, String> getCurrentCookiesAsMap() {
        Map<String, String> cookiesMap = new ConcurrentHashMap<>();
        // 尝试从CookieJar中加载所有已知域的Cookie
        // 这里的HttpUrl需要根据实际情况确定，例如目标网站的域名
        // 由于Cloudflare挑战通常是针对主域名，可以尝试一个通用URL
        HttpUrl dummyUrl = HttpUrl.parse(challengeUrl);
        if (dummyUrl == null) { // Fallback if challengeUrl is not a valid HttpUrl
            dummyUrl = HttpUrl.parse("https://example.com"); // Fallback to a valid dummy URL
        }

        if (dummyUrl != null) { // Ensure dummyUrl is not null
            List<Cookie> cookies = currentCookieJar.loadForRequest(dummyUrl);
            for (Cookie cookie : cookies) {
                cookiesMap.put(cookie.name(), cookie.value());
            }
        }
        return Collections.unmodifiableMap(cookiesMap);
    }

    /**
     * 定义Cloudflare挑战解决器的接口。
     * 用户需要实现此接口来提供解决Cloudflare挑战的逻辑。
     */
    @FunctionalInterface
    public interface CloudflareChallengeSolver {
        /**
         * 解决Cloudflare挑战。
         *
         * @param challengeException 包含挑战信息的异常
         * @return 解决挑战后获得的会话信息，例如新的Cookies (Map<String, String>) 和 Headers (Map<String, String>)。
         * 键可以是"cookies"和"headers"。如果返回null，表示解决失败或用户取消。
         */
        Map<String, Object> solve(CloudflareChallengeException challengeException);
    }
}